# koroFileHeader at Yungoal acer
# Create: 2021-09-26 14:57:49
# LastEdit: 2024-07-30 17:45:08
"""阿斯利康监控数据月度指标汇总

### 参考资料
#### Azure REST API reference
https://docs.microsoft.com/zh-cn/rest/api/monitor/metrics/list
#### Azure 监视 REST API 演练：
https://docs.microsoft.com/zh-cn/azure/azure-monitor/essentials/rest-api-walkthrough
"""
__author__ = '749B'

import os, sys
BASE_DIR = os.getcwd()
sys.path.append(BASE_DIR)

import argparse
import datetime
import dateutil.parser
import dateutil.tz
import urllib.parse

import msrestazure.azure_cloud
# pylint: disable = import-error
from azure_client import Azure_Client
from azure_client.models import Azure_Monitor_Report_Resource
from utils.env import init_environs
from utils.blueking import job_start, job_success, job_fail

from typing import Optional, List, Mapping, Tuple
from azure_client.models import _Params, _Field, _Unit, _Metric


class Report(Azure_Monitor_Report_Resource):
    
    fieldnames_base = ['名称', '类型', '资源组', '位置', '订阅']

    def call_hook(self, row: Mapping[str, str]) -> None:
        pass


def parse_time(start: str, end: str) -> Tuple[datetime.datetime, datetime.datetime]:
    if start and end:
        print("指定开始/结束时间")
        start_time = dateutil.parser.parse(start).astimezone(dateutil.tz.tzlocal())
        end_time = dateutil.parser.parse(end).astimezone(dateutil.tz.tzlocal())
        return start_time, end_time
    now = datetime.datetime.now(tz=dateutil.tz.tzlocal())
    this_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
    last_month_end = this_month - datetime.timedelta(days=1)
    last_month_start = last_month_end.replace(day=1)
    if not start:
        # 默认是上月时间
        print("未指定时间范围，默认上个月")
        return last_month_start, this_month
    if start.lower() == 'last month':
        print("指定时间范围，上个月")
        return last_month_start, this_month
    if start.isdigit() and start.strip('0') :
        print("指定时间范围，最近%s天" % start)
        start_time = now - datetime.timedelta(days=int(start))
        return start_time, now
    print("时间范围错误，默认最近3天")
    start_time = now - datetime.timedelta(days=3)
    return start_time, now

def init_argparse(args: Optional[List[str]] = None) -> argparse.Namespace:
    """初始化：命令行参数"""
    parser = argparse.ArgumentParser(description='Azure Monitor 指标数据汇总')

    parser.add_argument('--start', help='Start time')
    parser.add_argument('--end', help='End time')
    parser.add_argument('--interval', choices=['PT1M', 'PT5M', 'PT15M', 'PT30M', 'PT1H', 'PT6H', 'PT12H', 'P1D'], default='P1D', help='时间粒度')
    parser.add_argument('-e', '--envfile', help="存有用户认证信息的env文件的文件名")

    args = parser.parse_args(args)
    return args

def main(args: Optional[List[str]] = None) -> None:
    """主函数，解析命令行参数"""
    # 初始化命令行参数
    if args is None:
        # 蓝鲸作业平台有BUG，重做的任务，空着的参数里都会被填充null
        args = [arg for arg in sys.argv[1:] if arg != 'null' and not arg.endswith('=null')]
    args = init_argparse(args)

    envs = {}
    if 'JENKINS_HOME' not in os.environ:
        if not args.envfile:
            return job_fail("请提供存有用户认证信息的env文件的文件名")
        # 初始化环境变量
        envs = init_environs(args.envfile)
        if not envs:
            return job_fail("env文件解密错误")
        if envs['runtime_env'] == 'blueking':
            for key in args.__dict__.keys():
                if key.startswith('dev_'):
                    v = getattr(args, key)
                    if v:
                        print(f'{key}={v}: 不支持的命令行参数，已经忽略。', file=sys.stderr)
                        setattr(args, key, None)

    # 实例化客户端
    CLOUD = getattr(msrestazure.azure_cloud, os.environ.get('CLOUD_NAME', envs.get('cloud_name')))
    client = Azure_Client(CLOUD)

    # 根据指定的开始时间和结束时间计算时间范围
    start_time, end_time = parse_time(args.start, args.end)
    # 打印时间跨度和粒度
    start_display = start_time.strftime('%m/%d %H:%M')
    end_display = end_time.strftime('%m/%d %H:%M')
    print(f'本地时间: {start_display} - {end_display}')
    print(f'时间粒度: ({args.interval})')
    print()
    # Iso 8601时间格式，时区前面不能有Z
    start_timespan = start_time.strftime("%Y-%m-%dT%H:%M:%S%z")
    end_timespan = end_time.strftime("%Y-%m-%dT%H:%M:%S%z")
    timespan = urllib.parse.quote(f'{start_timespan}/{end_timespan}')
    # print(start_timespan, end_timespan, timespan)
    # return

    # 打印Azure Monitor报告
    # Analysis Services，单位换算是1000进制，而不是1024
    analysis_services_memory = _Metric(
        _Params('memory_metric', timespan, 'Maximum,Average', args.interval, 'data'),
        [_Field('MemoryMax', 'maximum', 'maximum'), _Field('MemoryAvg', 'average', 'average')],
        _Unit(1000, ['B', 'KB', 'MB', 'GB', 'TB'], ' '),
        )
    Report("microsoft.analysisservices/servers", [analysis_services_memory])(client)
    print()
    # Application Insights
    application_insights_dependencies = _Metric(
        _Params('dependencies/count', timespan, 'count', args.interval, 'data'),
        [_Field('服务器请求', 'count', 'sum')],
        _Unit(1000, ['', 'k'], '')
    )
    Report("microsoft.insights/components", [application_insights_dependencies])(client)
    print()
    # Azure Databricks 服务，无监控指标
    Report("microsoft.databricks/workspaces", [])(client)
    print()
    # Kubernetes 服务，这个指标没有1天的汇聚时间，最长12小时
    kubernetes_service_cpu = _Metric(
        _Params('node_cpu_usage_percentage', timespan, 'Maximum,Average', 'PT12H' if args.interval == 'P1D' else args.interval, 'data'),
        [_Field('MemoryMax', 'maximum', 'maximum'), _Field('MemoryAvg', 'average', 'average')],
        _Unit(1, ['%'], '')
    )
    Report("microsoft.containerservice/managedclusters", [kubernetes_service_cpu])(client)
    print()
    # Log Analytics 工作区
    Report("microsoft.operationalinsights/workspaces", [])(client)
    print()
    # Power BI Embedded
    power_BI_embedded_qpc = _Metric(
        _Params('qpu_metric', timespan, 'Maximum', args.interval, 'data'),
        [_Field('QPU(MAX)', 'maximum', 'maximum')],
        None
    )
    Report("microsoft.powerbidedicated/capacities", [power_BI_embedded_qpc])(client)
    print()
    # 负载均衡器，
    load_balancer_packet_count = _Metric(
        _Params('PacketCount', timespan, 'Total', args.interval, 'data'),
        [_Field('Packet Count(Total)', 'total', 'sum')],
        _Unit(1000, ['', 'K', 'M', 'G'],'')
    )
    Report("microsoft.network/loadbalancers", [load_balancer_packet_count])(client)
    print()
    # 函数应用
    function_app_memory = _Metric(
        _Params('MemoryWorkingSet', timespan, 'Maximum,Average', args.interval, 'data'),
        [_Field('MemoryMax', 'maximum', 'maximum'), _Field('MemoryAvg', 'average', 'average')],
        _Unit(1000, ['B', 'KB', 'MB', 'GB', 'TB'], ' '),
    )
    function_app_response = _Metric(
        _Params('HttpResponseTime', timespan, 'Maximum,Average', args.interval, 'data'),
        [_Field('Response Time MAX', 'maximum', 'maximum'), _Field('Response Time AVG', 'average', 'average')],
        _Unit(0.001, ['秒', '毫秒'], ' '),
    )
    Report("microsoft.web/sites/kind=functionapp", [function_app_memory, function_app_response])(client)
    print()
    # 机器学习
    machine_learning_cores = _Metric(
        _Params('Active Cores', timespan, 'Total', args.interval, 'data'),
        [_Field('Active Cores', 'total', 'sum')],
        None
    )
    Report("microsoft.machinelearningservices/workspaces", [machine_learning_cores])(client)
    print()
    # 解决方案
    Report("microsoft.operationsmanagement/solutions", [])(client)
    print()
    # 流式处理终结点，流式处理端点
    Report("microsoft.media/mediaservices/streamingendpoints", [])(client)
    print()
    # 逻辑应用
    logic_apps_actions_failed = _Metric(
        _Params('ActionsFailed', timespan, 'Count', args.interval, 'data'),
        [_Field('Actions Failed', 'count', 'sum')],
        None
    )
    Report("microsoft.logic/workflows", [logic_apps_actions_failed])(client)
    print()
    # 媒体服务
    media_services_live = _Metric(
        _Params('ChannelsAndLiveEventsCount', timespan, 'Average', args.interval, 'data'),
        [_Field('Live event count', 'average', 'average')],
        None
    )
    Report("microsoft.media/mediaservices", [media_services_live])(client)
    print()
    # 数据工厂(V2)
    data_factory_v2_pipeline = _Metric(
        _Params('PipelineFailedRuns', timespan, 'Count', args.interval, 'data'),
        [_Field('Failed pipeline runs metrics', 'count', 'sum')],
        None,
    )
    Report("microsoft.datafactory/factories", [data_factory_v2_pipeline])(client)
    print()
    # 搜索服务，官方叫：认知搜索
    cognitive_search_qps = _Metric(
        _Params('SearchQueriesPerSecond', timespan, 'Average', args.interval, 'data'),
        [_Field('Search queries per sec', 'average', 'average')],
        _Unit(1, ['/s'], ''),
    )
    Report("microsoft.search/searchservices", [cognitive_search_qps])(client)
    print()
    # 应用程序网关
    application_gateway_cpu = _Metric(
        _Params('CpuUtilization', timespan, 'Average', args.interval, 'data'),
        [_Field('CpuAvg', 'average', 'average')],
        _Unit(1, ['%'], ''),
    )
    Report("microsoft.network/applicationgateways", [application_gateway_cpu])(client)
    print()
    # 应用服务
    app_service_response_time = _Metric(
        _Params('HttpResponseTime', timespan, 'Maximum,Average', args.interval, 'data'),
        [_Field('Response Time MAX', 'maximum', 'maximum'), _Field('Response Time AVG', 'average', 'average')],
        _Unit(0.001, ['秒', '毫秒'], ' '),
    )
    Report("microsoft.web/sites/kind=app", [app_service_response_time])(client)
    print()
    # 应用服务(槽)
    app_service_slot_request = _Metric(
        _Params('Requests', timespan, 'Total', args.interval, 'data'),
        [_Field('Requests', 'total', 'sum')],
        None,
    )
    Report("microsoft.web/sites/slots", [app_service_slot_request])(client)
    print()
    # 应用服务计划
    app_service_plan_cpu = _Metric(
        _Params('CpuPercentage', timespan, 'Maximum,Average', args.interval, 'data'),
        [_Field('CpuMax', 'maximum', 'maximum'), _Field('CpuAvg', 'average', 'average')],
        _Unit(1, ['%'], ''),
    )
    app_service_plan_memory = _Metric(
        _Params('MemoryPercentage', timespan, 'Maximum,Average', args.interval, 'data'),
        [_Field('MemoryMax', 'maximum', 'maximum'), _Field('MemoryAvg', 'average', 'average')],
        _Unit(1, ['%'], ''),
    )
    Report("microsoft.web/serverfarms", [app_service_plan_cpu, app_service_plan_memory])(client)
    print()


if __name__ == '__main__':

    job_start()

    ###### 可在此处开始编写您的脚本逻辑代码
    ###### iJobs中执行脚本成功和失败的标准只取决于脚本最后一条执行语句的返回值
    ###### 如果返回值为0，则认为此脚本执行成功，如果非0，则认为脚本执行失败
    
    main()
    job_success()


